/**
 * @author: hdh
 * @date: 2022-03-09 8:57
 */
package com.yy.QSManage.service.base.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yy.QSManage.dao.LocalBaseMapper;
import com.yy.QSManage.enums.ErrorCodeEnum;
import com.yy.QSManage.exception.ServiceException;
import com.yy.QSManage.model.entity.FaSysGrid;
import com.yy.QSManage.model.entity.FaSysMember;
import com.yy.QSManage.service.base.BaseService;
import com.yy.QSManage.tool.RequestBuffUtil;
import org.apache.ibatis.binding.BindingException;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;


/**
 * {阐述类的作用}
 * @author: HuDeHong
 * @date: 2022-03-09 8:57
 */
public class BaseServiceImpl<M extends LocalBaseMapper<T>, T> extends ServiceImpl<M, T> implements BaseService<T> {

    @Autowired
    private RequestBuffUtil requestBuffUtil;

    @Override
    public void ifExist(SFunction<T, Object> field, Object param, String errMsg) {
        if(Objects.nonNull(getByParam(field, param, false))) throw new ServiceException(errMsg);
    }

    @Override
    public T ifNotExist(SFunction<T, Object> field, Object param, String errMsg) {
        T t = getByParam(field, param, false);
        if(Objects.isNull(t)) throw new ServiceException(errMsg);
        return t;
    }

    @Override
    public T ifNotExist(SFunction<T, Object> field, Object param, ErrorCodeEnum errorCodeEnum) {
        T t = getByParam(field, param, false);
        if(Objects.isNull(t)) throw new ServiceException(errorCodeEnum);
        return t;
    }

    @Override
    public boolean ifExist(SFunction<T, Object> field, Object param) {
        List<T> ts = listByParam(field, param);
        if(Objects.isNull(ts) || ts.size() == 0){
            return false;
        }
        return true;
    }

    @Override
    public boolean ifExist(String field, Object param) {
        List<T> ts = listByParam(field, param);
        if(Objects.isNull(ts) || ts.size() == 0){
            return false;
        }
        return true;
    }

    @Override
    public T ifExist(String id, SFunction<T, Object> field, Object param, String errMsg) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        qw.apply("id={0}", id);
        qw.lambda().eq(field, param);
        T t = getOne(qw, false);
        if(null == t){
            throw new ServiceException(StrUtil.isNotBlank(errMsg) ?errMsg:"数据不存在！");
        }
        return t;
    }

    @Override
    public List<T> ifExist(List<String> ids, SFunction<T, Object> field, Object param, String errMsg) {
        List<T> ts = new ArrayList<>();
        ids.forEach(item->{
            ts.add(ifExist(item, field, param, errMsg));
        });
        return ts;
    }

    @Override
    public void ifRepeat(SFunction<T, Object> field, Object param, String errMsg) {
        List<T> ts = listByParam(field, param);
        if(!Objects.isNull(ts) && ts.size() > 0){
            throw new ServiceException(StrUtil.isNotBlank(errMsg) ?errMsg:"数据重复！");
        }
    }

    @Override
    public boolean ifRepeat(SFunction<T, Object> field, Object param) {
        List<T> ts = listByParam(field, param);
        if(!Objects.isNull(ts) && ts.size() > 0){
            return true;
        }
        return false;
    }

    @Override
    public boolean ifRepeatExcludeId(SFunction<T, Object> field, Object param, String id) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        qw.ne("id", id)
                .lambda().eq(field, param);
        List<T> ts = baseMapper.selectList(qw);
        if(!Objects.isNull(ts) && ts.size() > 0){
            return true;
        }
        return false;
    }

    @Override
    public boolean ifRepeatExcludeId(String field, Object param, String id) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        qw.ne("id", id)
                .eq(field, param);
        List<T> ts = baseMapper.selectList(qw);
        if(!Objects.isNull(ts) && ts.size() > 0){
            return true;
        }
        return false;
    }

    @Override
    public void ifRepeatExcludeId(SFunction<T, Object> field, Object param, String id, String errMsg) {
        if(ifRepeatExcludeId(field, param, id)){
            throw new ServiceException(StrUtil.isNotBlank(errMsg) ?errMsg:"数据重复！");
        }
    }

    @Override
    public T getByParam(SFunction<T, Object> field, Object param) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        lambda.eq(field, param);
        return getOne(lambda);
    }

    @Override
    public T getByParam(String field, Object param) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        qw.eq(field, param);
        return getOne(qw);
    }

    @Override
    public T getByParam(SFunction<T, Object> field, Object param, boolean throwEx) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        lambda.eq(field, param);
        return getOne(lambda, throwEx);
    }

    @Override
    public List<T> listByParam(SFunction<T, Object> field, Object param) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        if(Objects.isNull(param)){
            lambda.isNull(field);
        }else{
            lambda.eq(field, param);
        }
        return baseMapper.selectList(lambda);
    }

    @Override
    public List<T> listByParam(String field, Object param) {
        return listByParamOrder(field,param,null,"desc");
    }

    @Override
    public List<T> listByParamAsc(String field, Object param) {
        return listByParamOrder(field,param,null,"asc");
    }

    @Override
    public List<T> listByParamDesc(String field, Object param, String orderField) {
        return listByParamOrder(field,param,orderField,"desc");
    }

    @Override
    public List<T> listByParamAsc(String field, Object param, String orderField) {
        return listByParamOrder(field,param,orderField,"asc");
    }

    @Override
    public List<T> listByParamOrder(String field, Object param, String orderField, String order) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        // 参数插入
        if(Objects.isNull(param)){
            qw.isNull(field);
        }else{
            qw.eq(field, param);
        }
        // 排序规则插入
        if(Objects.isNull(order) && Objects.isNull(orderField)){
            // 默认排序
            qw.orderByDesc(defaultSort());
        } else if (Objects.nonNull(order) && Objects.isNull(orderField)) {
            // 自定义排序
            boolean isAsc = "asc".equals(order);
            qw.orderBy(true,isAsc,defaultSort());
        }else if(Objects.isNull(order) && Objects.nonNull(orderField)){
            // 自定义排序
            qw.orderBy(true,false,orderField);
        } else{
            // 自定义排序
            boolean isAsc = "asc".equals(order);
            qw.orderBy(true,isAsc,orderField);
        }
        return baseMapper.selectList(qw);
    }

    @Override
    public List<T> listInParam(SFunction<T, Object> field, Object... param) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        if(Objects.isNull(param)){
            lambda.isNull(field);
        }else{
            lambda.in(field, param);
        }
        return baseMapper.selectList(lambda);
    }

    @Override
    public List<T> listInParam(SFunction<T, Object> field, Collection<?> param) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        if(Objects.isNull(param)){
            lambda.isNull(field);
        }else{
            lambda.in(field, param);
        }
        return baseMapper.selectList(lambda);
    }

    @Override
    public List<T> listNotInParam(SFunction<T, Object> field, Object... param) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        if(Objects.isNull(param)){
            lambda.isNotNull(field);
        }else{
            lambda.notIn(field, param);
        }
        return baseMapper.selectList(lambda);
    }

    @Override
    public List<T> listNotInParam(SFunction<T, Object> field, SFunction<T, Object> orderDesc, Object... param) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        if(Objects.isNull(param)){
            lambda.isNotNull(field);
        }else{
            lambda.notIn(field, param);
        }
        lambda.orderByDesc(orderDesc);
        return baseMapper.selectList(lambda);
    }

    @Override
    public List<T> listLikeParam(SFunction<T, Object> field, Object param) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        if(Objects.isNull(param)){
            lambda.isNull(field);
        }else{
            lambda.like(field, param);
        }
        return baseMapper.selectList(lambda);
    }

    @Override
    public T getOneDesc(SFunction<T, Object> sortParam) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        lambda.orderByDesc(sortParam)
                .last("limit 1");
        return getOne(lambda);
    }

    @Override
    public T getOneAsc(SFunction<T, Object> sortParam) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        lambda.orderByAsc(sortParam)
                .last("limit 1");
        return getOne(lambda);
    }

    @Override
    public T getOneDesc(SFunction<T, Object> field, Object param, SFunction<T, Object> sortParam) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        lambda.eq(field, param)
                .orderByDesc(sortParam)
                .last("limit 1");
        return getOne(lambda);
    }

    @Override
    public T getOneAsc(SFunction<T, Object> field, Object param, SFunction<T, Object> sortParam) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        lambda.eq(field, param)
                .orderByAsc(sortParam)
                .last("limit 1");
        return getOne(lambda);
    }

    @Override
    public T getDelByParam(SFunction<T, Object> field, Object param) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        qw.eq("is_delete", 1)
        .lambda().eq(field, param);
        return getOne(qw);
    }

    @Override
    public void removeByParam(SFunction<T, Object> field, Object param) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        lambda.eq(field, param);
        baseMapper.delete(lambda);
    }

    @Override
    public T randomExtraction() {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        int count = (int)count();
        int i = RandomUtil.randomInt(0, count - 1);
        lambda.last("limit "+ i +",1");
        return getOne(lambda);
    }

    @Override
    public T randomExtraction(SFunction<T, Object> field, Object param) {
        LambdaQueryWrapper<T> lambda = new LambdaQueryWrapper<>();
        lambda.eq(field, param);
        int count = (int)count(lambda);
        if(count < 1){
            return null;
        }
        if(count == 1){
            return getOne(lambda);
        }
        lambda = new LambdaQueryWrapper<>();
        int i = RandomUtil.randomInt(0, count - 1);
        lambda.eq(field, param)
                .last("limit "+ i +",1");
        return getOne(lambda);
    }

    @Override
    public IPage<T> page(Page page, T t, FaSysGrid grid) {
        IPage<T> pageData;
        try {
            pageData = baseMapper.page(page, t);
        }catch (BindingException e){
            // 自定义分页查询不存在，使用系统默认分页查询
            QueryWrapper<T> qw = new QueryWrapper<>();
            // 拼接查询字段
            qw.select(joinQueryField(grid));
            // 默认排序
            qw.orderByDesc(defaultSort());
            // 获取网格查询配置
            String queryJson = grid.getQueryJson();
            JSONArray queryJsonArr = new JSONArray(queryJson);
            // 扩展数据
            Object extend = ReflectUtil.getFieldValue(t, "extend");
            // 构造查询条件
            for (Object fieldObj : queryJsonArr) {
                JSONObject field = new JSONObject(fieldObj);
                // 字段名
                String fieldName = field.getStr("field");
                // 下划线链接字段名
                String fieldNameSql = StrUtil.toUnderlineCase(fieldName);
                // 字段值
                Object fieldValue = ReflectUtil.getFieldValue(t, fieldName);
                // 判断查询值是否在扩展字段内
                Object extendFieldValue = JSONUtil.parseObj(extend).get(fieldName);
                if(Objects.nonNull(extendFieldValue)){
                    // 优先使用扩展字段内部查询值
                    fieldValue = extendFieldValue;
                }
                // 查询方式
                String queryMode = field.getStr("queryMode");

                // 排除空条件
                if(Objects.isNull(fieldValue)){
                    continue;
                }
                if(fieldValue instanceof String && StrUtil.isBlank(fieldValue.toString())){
                    continue;
                }
                if(fieldValue instanceof Array){
                    JSONArray jsonArray = JSONUtil.parseArray(fieldValue);
                    if(jsonArray.isEmpty()){
                        continue;
                    }
                }
                switch (queryMode){
                    case "=":
                        qw.eq(fieldNameSql, fieldValue);
                        break;
                    case "%like%":
                        qw.like(fieldNameSql, fieldValue);
                        break;
                    case "%like":
                        qw.likeLeft(fieldNameSql, fieldValue);
                        break;
                    case "like%":
                        qw.likeRight(fieldNameSql, fieldValue);
                        break;
                    case ">":
                        qw.gt(fieldNameSql, fieldValue);
                        break;
                    case "<":
                        qw.lt(fieldNameSql, fieldValue);
                        break;
                    case "in":
                        JSONArray ins;
                        try {
                            ins = JSONUtil.parseArray(fieldValue);
                        }catch (JSONException jsonException){
                            ins = new JSONArray().put(fieldValue);
                        }
                        qw.in(fieldNameSql,ins);
                        break;
                    case "between":
                        JSONArray between = JSONUtil.parseArray(fieldValue);
                        qw.between(fieldNameSql, between.get(0), between.get(1));
                        break;
                    default:
                        throw new ServiceException(StrUtil.format("未添加此查询 {} 方式处理逻辑！", queryMode));
                }
            }
            // 数据隔离
            String tableJson = grid.getTableJson();
            JSONObject tableJsonObj = new JSONObject(tableJson);
            // 判断是否开启数据隔离
            if((boolean)tableJsonObj.getByPath("dataLsolation.enable")){
                // 获取隔离关联字段
                String field = tableJsonObj.getByPath("dataLsolation.field").toString();
                String joinField = tableJsonObj.getByPath("dataLsolation.joinField").toString();
                // 获取当前登录用户信息
                FaSysMember tokenMember = requestBuffUtil.getTokenMember();
                // 获取用户信息关联字段值
                Object fieldValue = ReflectUtil.getFieldValue(tokenMember, field);
                // 下划线链接字段名
                String joinFieldSql = StrUtil.toUnderlineCase(joinField);
                qw.eq(joinFieldSql, fieldValue);
            }
            pageData = baseMapper.selectPage(page, qw);
        }
        return pageData;
    }

    @Override
    public IPage<T> pageNoSql(Page page) {
        return page(page);
    }

    @Override
    public void updateById(SFunction<T, Object> field, Object param, String id) {
        UpdateWrapper<T> lambda = new UpdateWrapper<>();
        lambda.eq("id", id)
                .lambda().set(field, param);
        update(lambda);
    }

    @Override
    public void updateBatchByIds(SFunction<T, Object> field, Object param, Collection<String> ids) {
        UpdateWrapper<T> lambda = new UpdateWrapper<>();
        lambda.in("id", ids)
                .lambda().set(field, param);
        update(lambda);
    }

    @Override
    public T getGtOne(String field, Object param) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        qw.gt(field, param)
                .orderByAsc(field);
        return list(qw).get(0);
    }

    @Override
    public T getLtOne(String field, Object param) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        qw.lt(field, param)
                .orderByDesc(field);
        return list(qw).get(0);
    }

    @Override
    public T getMax(String field) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        qw.orderByDesc(field);
        return list(qw).get(0);
    }

    @Override
    public T getMin(String field) {
        QueryWrapper<T> qw = new QueryWrapper<>();
        qw.orderByAsc(field);
        return list(qw).get(0);
    }

    @Override
    public String getCode(SFunction<T, Object> field, int num) {
        String code;
        int count = 0;
        while (true){
            if(count == 11){
                throw new ServiceException("生成code已重复 10 次，请延长生成code长度防止重复！");
            }
            // 生成code
            code = RandomUtil.randomStringUpper(num);
            // 判断是否存在
            if(!ifRepeat(field, code)){
                return code;
            }
            count ++;
        }
    }
    @Override
    public String getCodes(SFunction<T, Object> field, int num, List<String> tempList) {
        String code;
        int count = 0;
        while (true){
            if(count == 11){
                throw new ServiceException("生成code已重复 10 次，请延长生成code长度防止重复！");
            }
            code = getCode(field, num);
            if(!tempList.contains(code)){
                tempList.add(code);
                return code;
            }
            count ++;
        }
    }

    /**
     * 拼接查询字段
     * @param grid 网格信息
     * @return
     */
    private String joinQueryField(FaSysGrid grid){
        String fieldJson = grid.getFieldJson();
        JSONArray objects = JSONUtil.parseArray(fieldJson);
        String queryFieldStr = "";
        for (Object object : objects) {
            JSONObject entries = JSONUtil.parseObj(object);
            String field = entries.getStr("field");
            // 判断该字段是否存在
            if(Objects.nonNull(ReflectUtil.getField(getEClass(), field))){
                queryFieldStr = queryFieldStr.concat(StrUtil.toUnderlineCase(field)).concat(",");
            }
        }
        // 删除最后一个逗号
        int length = queryFieldStr.length();
        queryFieldStr = queryFieldStr.substring(0, length - 1);
        return queryFieldStr;
    }

    /**
     * 默认排序
     * @return 默认排序字段
     */
    private String defaultSort(){
        Object sort = ReflectUtil.getField(getEClass(), "sort");
        if(Objects.nonNull(sort)){
            return "sort";
        }else{
            return "update_time";
        }
    }

    public Class<?> getEClass() {

        //get the Class object of this own class
        Class<?> thisClass = this.getClass();

        //get the Type Object of supper class
        Type superClassType = thisClass.getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType)superClassType;

        //get the Generic Type array
        Type[] genTypeArr = pt.getActualTypeArguments();
        Type genType = genTypeArr[1];
        if (false == genType instanceof Class){
            return Object.class;
        }

        return (Class<Object>) genType;
    }

}
